package com.jsu.forum.service.impl;

import com.baidu.aip.contentcensor.AipContentCensor;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.jsu.forum.config.baiduApi;
import com.jsu.forum.mapper.CountMapper;
import com.jsu.forum.mapper.PassageMapper;
import com.jsu.forum.mapper.ScoreMapper;
import com.jsu.forum.service.PassageService;
import com.jsu.server.WebSocketServer;
import com.jsu.user.service.impl.WebUserServiceImpl;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Client;
import lombok.extern.slf4j.Slf4j;
import org.example.model.common.dtos.ResponseResult;
import org.example.model.common.enums.QINiuYunEnum;
import org.example.model.common.enums.RedisCodeEnum;
import org.example.model.common.enums.WebHttpCodeEnum;
import org.example.model.forum.dto.ForumDto;
import org.example.model.forum.dto.PassageDto;
import org.example.model.forum.dto.ScoreDto;
import org.example.model.forum.enums.PassageEnum;
import org.example.model.forum.pojo.Count;
import org.example.model.forum.pojo.Passage;
import org.example.model.forum.pojo.PassageScore;
import org.example.model.user.pojo.User;
import org.example.utils.common.*;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Date;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PassageServiceImpl extends ServiceImpl<PassageMapper, Passage> implements PassageService {
    @Autowired
    private StringRedisTemplate redisCache;
    @Autowired(required = false)
    private WebUserServiceImpl webUserService;
    @Autowired
    private CountMapper countMapper;
    @Autowired
    private ScoreMapper scoreMapper;
    private static final ObjectMapper mapper = new ObjectMapper();

    AipContentCensor client = new AipContentCensor(baiduApi.APP_ID,baiduApi.API_KEY, baiduApi.SECRET_KEY);

    /**
     * 发布文章
     * @param forumDto
     * @return
     */
    @Override
    public ResponseResult addPassage(ForumDto forumDto) {
        if(forumDto.getContext()==null)
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"文章内容不能为空");
        if(forumDto.getImage().size()>0){
            forumDto = checkImage(forumDto);
        }
        //审核文章内容
        forumDto = checkPassage(forumDto);
        //需要人工审核
        if(forumDto.getState().equals(QINiuYunEnum.REVIEW.getMsg())){

            WebSocketServer.sendToAdminPassage();

            return ResponseResult.okResult(200,"文章正在审核中");
        } else if (forumDto.getState().equals(QINiuYunEnum.BLOCK.getMsg())) {
            //审核不通过
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"审核不通过");
        }
        //存储到Redis中
        forumDto.setPkId(Integer.parseInt(IdsUtils.creatCode()));
        forumDto.setCommentCount(0);
        forumDto.setLikeCount(0);
        forumDto.setCount(0);
        LocalDateTime now = LocalDateTime.now();
        Date date = Date.valueOf(now.toLocalDate());
        forumDto.setPublishTime(date);

        log.info(forumDto.toString());
        String key = RedisCodeEnum.FORUM_PASSAGE.getMsg()+forumDto.getPkId();
        String json = null;
        try {
            json = mapper.writeValueAsString(forumDto);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        redisCache.opsForValue().set(key,json);
        //将forumdto转换成passage
        Passage passage = convertForumDtoToPassage(forumDto);
        log.info(passage.toString());

        //存储到数据库中
        int count = getBaseMapper().insert(passage);
        if (count<=0) {
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"发布文章失败");
        }
        return ResponseResult.okResult(200,"发布成功");
    }

    /**
     * 根据不同的请求类型，返回不同的passage集合
     * @param passageDto
     * @return
     */
    @Override
    public ResponseResult getPassage(PassageDto passageDto,String token) {
        switch (passageDto.getType()){
            case PassageEnum.LATEST:
                return getLatestPassage(passageDto.getPage(),passageDto.getPageSize());
            case PassageEnum.HOT:
                return getHotPassage(passageDto.getPage(),passageDto.getPageSize(),token);
            case PassageEnum.ESSENCE:
                return getEssencePassage(passageDto.getPage(),passageDto.getPageSize());
            default:
                return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"没有该选项");
        }
    }

    /**
     * 刷新时，获取精华文章
     * @return
     */
    private ResponseResult getEssencePassage(int page, int pageSize) {
        //从redis中获取精华文章
        String key = RedisCodeEnum.FORUM_PASSAGE.getMsg();
        List<String> list = redisCache.opsForList().range (key,0,-1);
        if(list.size() == 0){
            // 创建分页对象
            Page<Passage> passagePage = new Page<>(page, pageSize);
            // 创建排序条件
            QueryWrapper<Passage> wrapper = new QueryWrapper<>();
            wrapper.orderByDesc("score"); // 根据评分降序排序
            // 执行分页查询
            getBaseMapper().selectPage(passagePage, wrapper);
            List<Passage> records = passagePage.getRecords();
            // 返回结果
            return ResponseResult.okResult(convertPassageListToForumDtoList(records));
        }
        //转化成forumDto对象
        List<ForumDto> forumDtos = new ArrayList<>();
        for(String a : list){
            ForumDto forumDto = null;
            try {
                forumDto = mapper.readValue(a, ForumDto.class);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            forumDtos.add(forumDto);
        }
        //根据评分进行排序
        Collections.sort(forumDtos, Comparator.comparingDouble(ForumDto::getScore).reversed());
        List<ForumDto> forumDtos1 = forumDtos.subList(pageSize * (page - 1), Math.min(pageSize * page, forumDtos.size()));
        if(forumDtos1.size() == 0)
            return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"没有了");
        return ResponseResult.okResult(forumDtos1);
    }

    private List<ForumDto> convertPassageListToForumDtoList(List<Passage> records) {
        List<ForumDto> forumDtos = new ArrayList<>();
        for (Passage passage : records) {
            log.info(passage.toString());
            ForumDto forumDto = convertPassageToForumFto(passage);
            log.info(forumDto.toString());
            forumDtos.add(forumDto);
        }
        return forumDtos;
    }


    /**
     * 刷新时，获取热门的文章
     * @return
     */
    private ResponseResult getHotPassage(int page, int pageSize,String token) {
        //智能推荐，协同过滤算法
        List<ScoreDto> scoreDtos = new ArrayList<>();//存储算法结果
        List<ScoreDto> scoreDtoList = new ArrayList<>();//存储计算结果

        //获取用户评分的信息
        List<PassageScore> scores = scoreMapper.selectList(null);
        if (scores.size() == 0) {
            //按照浏览量，点赞量和评分进行排序
            List<Passage> passages = getBaseMapper().selectList(null);
            // 计算得分并保存到 PassageScore 列表中
            for (Passage passage : passages) {
                double score = calculateScore(passage.getCount(), passage.getLikeCount(), passage.getScore());
                scoreDtos.add(new ScoreDto(passage, score));
            }
            // 按得分从高到低排序
            Collections.sort(scoreDtos, Comparator.comparingDouble(ScoreDto::getScore).reversed());
        } else {
            Map<Integer, Map<Integer, Double>> resultMap = scores.stream()
                    .collect(Collectors.groupingBy(PassageScore::getUserId, // 根据 userId 分组
                            Collectors.toMap(PassageScore::getPassageId, // Map 的键是 passageId
                                    PassageScore::getScore))); // Map 的值是 score
            // 创建推荐系统对象
            RecommenderSystem recommenderSystem = new RecommenderSystem(resultMap, 10);
            User user = (User) webUserService.findUser(token).getData();
            int userId = user.getPkId();
            // 获取推荐结果
            Map<Integer, Double> recommendedItems = recommenderSystem.recommendItems(userId);
            //将recommendedItems转化成List<scoreDto>
            // 遍历 recommendedItems 中的每个键值对
            for (Map.Entry<Integer, Double> entry : recommendedItems.entrySet()) {
                Integer passageId = entry.getKey();
                Double score = entry.getValue();
                // 根据 passageID 获取对应的 Passage 对象，这里假设 passages 是已经存在的 Passage 列表
                Passage passage = getBaseMapper().selectById(passageId);
                // 如果找到了对应的 Passage 对象，则构造 ScoreDto 对象，并添加到列表中
                if (passage != null) {
                    ScoreDto scoreDto = new ScoreDto(passage, score);
                    scoreDtoList.add(scoreDto);
                }
            }
            // 对 scoreDtoList 进行排序，按照 score 降序排列
            Collections.sort(scoreDtoList, Comparator.comparing(ScoreDto::getScore).reversed());
        }

        //排除已经存在的 Passage
        List<Passage> result = new ArrayList<>();
        Set<Integer> existingIds = new HashSet<>();
        for (ScoreDto scoreDto : scoreDtoList) {
            existingIds.add(scoreDto.getPassage().getPkId());
        }
        for (ScoreDto scoreDto : scoreDtos) {
            if (!existingIds.contains(scoreDto.getPassage().getPkId())) {
                result.add(scoreDto.getPassage());
            }
        }
        //将智能推荐的集合转化成List<Passage>
        List<Passage> passageList = new ArrayList<>();
        for (ScoreDto scoreDto : scoreDtoList) {
            passageList.add(scoreDto.getPassage());
        }
       result.addAll(passageList);
        //根据分页参数进行分页
        int start = (page - 1) * pageSize;
        int end = Math.min(start + pageSize, result.size());
        List<Passage> pageResult = result.subList(start, end);


        return ResponseResult.okResult(convertPassageListToForumDtoList(pageResult));
    }


    /**
     * 刷新时，获取最新的内容
     * @return
     */
    private ResponseResult getLatestPassage(int page, int pageSize) {
        //从redis中获取精华文章
        String key = RedisCodeEnum.FORUM_PASSAGE.getMsg();
        List<String> list = redisCache.opsForList().range (key,0,-1);
        if(list.size() == 0){
            // 创建分页对象
            Page<Passage> passagePage = new Page<>(page, pageSize);
            // 创建排序条件
            QueryWrapper<Passage> wrapper = new QueryWrapper<>();
            wrapper.orderByDesc("publish_time"); // 根据评分降序排序
            // 执行分页查询
            getBaseMapper().selectPage(passagePage, wrapper);
            List<Passage> records = passagePage.getRecords();
            // 返回结果
            return ResponseResult.okResult(convertPassageListToForumDtoList(records));
        }
        //转化成forumDto对象
        List<ForumDto> forumDtos = new ArrayList<>();
        for(String a : list){
            ForumDto forumDto = null;
            try {
                forumDto = mapper.readValue(a, ForumDto.class);
                log.info(forumDto.toString());
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            forumDtos.add(forumDto);
        }
        //根据评分进行排序
        Collections.sort(forumDtos, Comparator.comparing(ForumDto::getPublishTime).reversed());
        List<ForumDto> forumDtos1 = forumDtos.subList(pageSize * (page - 1), Math.min(pageSize * page, forumDtos.size()));
        if(forumDtos1.size() == 0)
            return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"没有了");
        return ResponseResult.okResult(forumDtos1);
    }


    /**
     * 删除文章
     * @param id
     * @return
     */
    @Override
    public ResponseResult deletePassage(Integer id) {
        int count = getBaseMapper().deleteById(id);
        if (count<=0) {
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"删除失败");
        }
        return ResponseResult.okResult(200,"删除成功");
    }

    /**
     * 点赞
     * @param passageId
     * @return
     */
    @Override
    public boolean addLike(Integer passageId) {
        int count = getBaseMapper().addLike(passageId);
        if (count<=0) {
            return false;
        }
        return true;
    }

    /**
     * 取消点赞
     * @param
     * @return
     */
    @Override
    public boolean reduceLike(Integer passageId) {
        int count = getBaseMapper().reduceLike(passageId);
        if (count<=0) {
            return false;
        }
        return true;
    }

    /**
     * 更新浏览量
     * @param id
     * @return
     */
    @Override
    @Transactional
    public ResponseResult addCount(Integer id) {
        //实例化Count对象
        int countId = Integer.parseInt(IdsUtils.creatCode());
        int userId = 562296724;
//        int userId = webUserService.getUser().getPkId();
        Date time = Date.valueOf(String.valueOf(LocalDate.now()));
        Count c = new Count(countId,userId,id,time);
        //添加redis浏览记录
        String key = RedisCodeEnum.PASSAGE_COUNT.getMsg()+countId;
        String json = null;
        try {
            json = mapper.writeValueAsString(c);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        redisCache.opsForValue().set(key,json);
        //添加数据库记录
        int count2 = countMapper.insert(c);
        if (count2<=0) {
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"更新失败");
        }
        //更新数据库中文章浏览量
        int count = getBaseMapper().addCount(id);
        //更新redis中文章浏览量
        String key2 = RedisCodeEnum.FORUM_PASSAGE.getMsg()+id;
        redisCache.opsForValue().getOperations().delete(key2);
        Passage passage = getBaseMapper().selectById(id);
        ForumDto forumDto = convertPassageToForumFto(passage);
        String json2 = null;
        try {
            json2 = mapper.writeValueAsString(forumDto);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        redisCache.opsForValue().set(key2,json2);
        if (count<=0) {
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"更新失败");
        }
        return ResponseResult.okResult(200,"更新成功");
    }

    /**
     * 文章审核
     * @param
     * @return 文章审核结果
     */
    public ForumDto checkPassage(ForumDto passage) {
        //审核文本文字
        String result = null;
        try {
            result = BaiduUtil.checkTextContent(passage.getContext(),client);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        log.info("百度文本审核结果："+result);
        //获取文本审核结果
        String type = check(result);
        passage.setState(type);

        return passage;
    }

    /**
     * 图片审核
     * @param
     * @return 文章审核结果
     */
    public ForumDto checkImage(ForumDto passage) {
        //审核图片
        String result = null;
        try {
            result = BaiduUtil.checkImageUrl(passage.getImage(),client);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        log.info("百度图像审核结果："+result);
        //获取文本审核结果
        String type = check(result);
        passage.setState(type);
        return passage;
    }

    /**
     * 将 ForumDto 转换为 Passage 对象
     * @param forumDto
     * @return
     */
    public Passage convertForumDtoToPassage(ForumDto forumDto) {
        Passage passage = new Passage();
        passage.setContext(forumDto.getContext());
        passage.setAuthorId(forumDto.getAuthorId());
        passage.setPublishTime(forumDto.getPublishTime());
        passage.setLikeCount(forumDto.getLikeCount());
        passage.setCount(forumDto.getCount());
        passage.setCommentCount(forumDto.getCommentCount());
        passage.setState(forumDto.getState());
        passage.setScore(forumDto.getScore());
        passage.setPkId(forumDto.getPkId());
        passage.setAvatar(forumDto.getAvatar());
        passage.setAuthorName(forumDto.getName());

        // 将 List<String> 转换为多个字段
        if (forumDto.getImage() != null && !forumDto.getImage().isEmpty()) {
            int imageSize = forumDto.getImage().size();
            switch (imageSize) {
                case 1:
                    passage.setImage1(forumDto.getImage().get(0));
                    break;
                case 2:
                    passage.setImage1(forumDto.getImage().get(0));
                    passage.setImage2(forumDto.getImage().get(1));
                    break;
                case 3:
                    passage.setImage1(forumDto.getImage().get(0));
                    passage.setImage2(forumDto.getImage().get(1));
                    passage.setImage3(forumDto.getImage().get(2));
                    break;
                case 4:
                    passage.setImage1(forumDto.getImage().get(0));
                    passage.setImage2(forumDto.getImage().get(1));
                    passage.setImage3(forumDto.getImage().get(2));
                    passage.setImage4(forumDto.getImage().get(3));
                    break;
                case 5:
                    passage.setImage1(forumDto.getImage().get(0));
                    passage.setImage2(forumDto.getImage().get(1));
                    passage.setImage3(forumDto.getImage().get(2));
                    passage.setImage4(forumDto.getImage().get(3));
                    passage.setImage5(forumDto.getImage().get(4));
                    break;
                case 6:
                    passage.setImage1(forumDto.getImage().get(0));
                    passage.setImage2(forumDto.getImage().get(1));
                    passage.setImage3(forumDto.getImage().get(2));
                    passage.setImage4(forumDto.getImage().get(3));
                    passage.setImage5(forumDto.getImage().get(4));
                    passage.setImage6(forumDto.getImage().get(5));
                    break;
                default:
                    break;
            }
        }

        return passage;
    }

    /**
     * 将 Passage 对象转换为 ForumDto 对象
     * @param passage
     * @return
     */
    public ForumDto convertPassageToForumFto(Passage passage) {
        ForumDto forumDto = new ForumDto();
        forumDto.setPkId(passage.getPkId());
        forumDto.setContext(passage.getContext());
        forumDto.setAuthorId(passage.getAuthorId());
        forumDto.setPublishTime(passage.getPublishTime());
        forumDto.setLikeCount(passage.getLikeCount());
        forumDto.setCount(passage.getCount());
        forumDto.setCommentCount(passage.getCommentCount());
        forumDto.setState(passage.getState());
        forumDto.setScore(passage.getScore());
        forumDto.setAvatar(passage.getAvatar());
        forumDto.setName(passage.getAuthorName());

        // 将图片字段转换为 List<String>
        List<String> imageList = new ArrayList<>();
        if (passage.getImage1() != null) imageList.add(passage.getImage1());
        if (passage.getImage2() != null) imageList.add(passage.getImage2());
        if (passage.getImage3() != null) imageList.add(passage.getImage3());
        if (passage.getImage4() != null) imageList.add(passage.getImage4());
        if (passage.getImage5() != null) imageList.add(passage.getImage5());
        if (passage.getImage6() != null) imageList.add(passage.getImage6());
        forumDto.setImage(imageList);

        return forumDto;
    }


    /**
     * 获取文章审核结果
     * @param suggestion
     * @return 结果类型
     */
    public String check(String suggestion){
        switch (suggestion){
            case "不合规": return QINiuYunEnum.BLOCK.getMsg();
            case "疑似":return QINiuYunEnum.REVIEW.getMsg();
            case "合规":return QINiuYunEnum.PASS.getMsg();
            default:return QINiuYunEnum.REVIEW.getMsg();
        }
    }

    // 计算文章得分
    private static double calculateScore(int count, int likeCount, double score) {
        return (count * 0.3 + likeCount * 0.3 + score * 0.4);
    }


}
